package com.qiangesoft.security.filter;

import com.qiangesoft.security.exception.TokenException;
import com.qiangesoft.security.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * token过滤器
 *
 * @author qiangesoft
 * @date 2024-05-14
 */
public class TokenFilter extends BasicAuthenticationFilter {

    private final UserDetailsService userDetailsService;

    private final JwtUtil jwtUtil;

    public TokenFilter(AuthenticationManager authenticationManager, UserDetailsService userDetailsService, JwtUtil jwtUtil) {
        super(authenticationManager);
        this.userDetailsService = userDetailsService;
        this.jwtUtil = jwtUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String token = request.getHeader(jwtUtil.getHeader());
        if (token == null) {
            chain.doFilter(request, response);
            return;
        }

        // token异常
        Claims claims = jwtUtil.getClaimsByToken(token);
        if (claims == null) {
            throw new TokenException("token非法");
        }
        // token过期
        boolean expired = jwtUtil.isTokenExpired(claims);
        if (expired) {
            throw new TokenException("token已过期");
        }

        // 构建authenticationToken
        String username = claims.getSubject();
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);

        chain.doFilter(request, response);
    }
}